Harness Engineering:从 Agent Loop 到完整 Agent Runtime

本文整理自《最近折腾 Harness 的一些感受和思考》,梳理从最小 Agent Loop 到完整 Agent Runtime 的演进路径。

1. Harness 到底是什么?

最简单的 Agent,本质上就是一个 Loop:

while not finished:
    response = LLM(context, tools)

    if response contains tool_call:
        result = execute(tool_call)
        context += result
    else:
        return response

模型负责:

理解任务 → 决定下一步 → 调用工具 → 观察结果 → 继续判断

但真正做一个可用的 Agent 时,问题很快就会出现在 Loop 之外:

因此可以把 Harness 理解为:位于 Model 与真实执行环境之间,负责让 Model 能够稳定执行任务的一整套运行时能力。

一个比较清晰的划分是:

                Agent
                  │
          ┌───────┴───────┐
          │               │
        Model           Harness
          │               │
     思考 / 推理          执行环境
     判断 / 规划          Tool
                         Skill
                         Sandbox
                         State
                         Memory
                         Context
                         Permission
                         Artifact
                         Trace
                         Scheduling
                         ...

因此可以理解为:

Agent = Model + Harness

2. 只有一个 Shell / Execute

最开始,可以只给 Agent 一个 execute(command),例如 grepfindsedgitpythonnpmcurlwget

一个 Shell 实际上已经提供了非常强的组合能力。理论上,一个 execute 几乎可以操作整个计算环境——这也是为什么 Coding Agent 可以仅依赖 Shell + 文件编辑能力完成大量任务。

2.1 问题:安全

如果模型拥有 rmsshcurlwgetgitpipnpm,那么它实际上拥有非常大的执行权限。因此必须引入 Sandbox

Agent
  │
  ▼
Sandbox
  │
  ├── 文件系统隔离
  ├── 网络限制
  ├── CPU / Memory 限制
  ├── 进程隔离
  └── 权限限制

2.2 轮次太多,导致注意力偏移

Model → Shell → Result → Model → Shell → Result → Model

多轮 Shell 调用会导致 token 消耗过多、注意力偏移。

3. Structured Tool

Shell 虽然能力强,但有一个明显问题:很多确定性的事情,本来不应该让 LLM 每次自己推理。

例如 sed -n '1,200p' xxx。如果直接让模型操作 Shell,它需要自己处理:文件是否存在、是否太大、如何分页、如何截断、编码、路径、错误处理。

这些其实都是确定性的工程问题。因此开始把 Shell 能力封装成结构化 Tool:read_file()search()edit_file()download()browser() ……

例如:

read_file(
    path="config.yaml",
    start_line=1,
    end_line=100
)

Harness 可以自动处理分页、截断、编码、异常、路径、权限;Model 只需要表达:我要读取 config.yaml

核心原则:能确定性解决的问题,就不要让 LLM 每次重新推理。

3.1 Tool 带来的另一个能力:Permission

当所有操作都是结构化 Tool 后,就可以在 Tool 执行前增加拦截层:

LLM → Tool Call → Permission / Hook
                    │
              允许?
              ├── Yes → Execute
              └── No  → Reject / Ask User

例如 delete_database() 可以在执行前走 Permission Check → 需要人工确认 → Approve / Reject。

相比于 Prompt 里写「请不要执行危险操作」,准确性更高,也更安全。

3.2 Tool 太多怎么办?

Skill 的分治策略可以通过索引解决 tool 过多、不知道用哪个的问题,但频繁调用 skill 也会导致 token 消耗过多、注意力偏移。

于是可以让 LLM 生成一段编排代码:

LLM → 生成 orchestration logic
        → Search → Read → Filter → Batch → Retry → Dedup
        → 整理结果 → LLM

例如:

files = search("foo")

results = []

for file in files[:10]:
    content = read_file(file)
    if matches_condition(content):
        results.append(content)

return results

这里 LLM 不再参与每一次 read(file1)read(file2)read(file3)

4. LLM 和程序的职责边界

这是整个 Harness 设计中非常重要的一条原则。

LLM 负责不确定性,例如:用户真正想解决什么?这个错误意味着什么?应该选择哪个方案?下一步应该调查什么?当前结果是否足够?应该如何修改代码?

程序负责确定性,例如:循环、排序、过滤、并发、Retry、Backoff、Batch、Parse、Dedup、Cache、权限检查、资源限制。

5. Context Management

任务执行几十轮以后:

Context → 越来越长 → 超出窗口

于是需要 Context Builder、Compaction、Context Management。

6. Checkpoint / Resume

任务执行到一半:

Agent → Tool → Process Crash

如果没有持久化,任务全部丢失。于是需要 Checkpoint / Resume:

Task → Step 1 → Step 2 → Checkpoint → Step 3 → Crash

恢复后:Checkpoint → Step 3 → 继续执行

7. State

Agent 执行过程中,需要维护当前运行状态:当前任务、当前步骤、当前工具调用、当前结果、当前 Agent、当前执行上下文。

这就是 State——可以简单理解成 Agent 当前运行时状态。

8. Memory

如果任务跨 Session:

Session 1 → Session 结束 → Session 2

Agent 可能还需要知道:以前发生过什么、用户过去做过什么、之前形成了什么长期信息。于是产生 Memory

因此三者需要区分:

概念 含义
Context 当前这一次推理需要看到的信息
State 当前 Agent 的运行状态
Memory 跨运行 / 跨 Session 保留的信息

这三个概念非常容易混淆,但在长期运行 Agent 中必须进行区分。

9. Artifact

Agent 不一定只返回文本。它可能产生代码、HTML、PPT、PDF、图片、数据文件、报告——这些不能简单当成普通 LLM Response 处理。

因此需要 Artifact Lifecycle

生成 → 存储 → 版本管理 → 引用 → 修改 → 再次生成 → 交付

10. Multi-Agent / Orchestration

当一个 Agent 无法独立完成任务时:

Parent Agent
      │
 ┌────┼────┐
 ▼    ▼    ▼
Agent Agent Agent

就会出现 Agent Orchestration,需要解决:子 Agent 创建、任务分配、结果传递、状态管理、超时、失败处理、并发、资源限制。

这已经开始明显接近一个 Agent Runtime / Execution Platform

11. Trace / Observability

Agent 出现问题时,传统日志往往不够。例如:为什么 Agent 选择了这个 Tool?为什么连续调用了 20 次?为什么突然进入死循环?为什么最后结果错误?

需要记录 Model Input / Output、Tool Call / Result、State Change、Context、Latency、Token、Error。于是出现 Trace / Observability

这也是为什么 Agent 系统通常需要类似 LangSmith / Langfuse 这样的可观测性系统。

12. Eval / Regression

Harness 改了以后——Tool、Prompt、Skill、Context、Model 任一变化——Agent 可能昨天能完成、今天突然完成不了了。

因此需要 Eval / Regression Test:

修改 Harness → 运行 Agent Evaluation → 比较历史结果 → 判断是否退化

这使 Agent 工程逐渐具备传统软件工程中的 Test、Regression、CI/CD 属性。

13. Scheduling / Queue / Resource Governance

如果 Agent 任务只运行几秒,问题不大。但如果一个任务运行 30 分钟甚至几个小时,就需要 Queue、Scheduling、Timeout、Retry、Resource Governance、Concurrency Limit。

例如:

                    Scheduler
                       │
             ┌─────────┴─────────┐
             ▼                   ▼
          Agent A             Agent B
             │                   │
          Sandbox             Sandbox

此时 Harness 已经不只是一个 LLM + Tool Loop,而开始具备 Runtime、Scheduler、Executor、State Manager、Resource Manager 等基础设施属性。

14. Isolation

多用户、多 Agent 场景还需要进一步解决:User Identity、Permission、Tenant Isolation,以及 Filesystem / Process / Network / Resource Isolation。

例如:

User A → Agent A → Sandbox A
User B → Agent B → Sandbox B

不能让 Agent A 访问 Agent B 的数据。因此 Isolation 也是生产级 Harness 的重要组成部分。

15. Harness 的演进路线

把整个过程压缩起来:

T0  Shell
 ↓
T1  Sandbox + Structured Tool + Permission
 ↓
T2  Skill + Progressive Disclosure
 ↓
T3  Code Orchestration
 ↓
生产级 Harness
    Context / State / Memory / Checkpoint / Resume
    Artifact / Multi-Agent / Trace / Observability
    Eval / Regression / Scheduling / Queue
    Resource Governance / Isolation

16. Harness 的核心设计原则

整个演进过程实际上可以归纳成几条原则。

原则一:不要让 LLM 做确定性的工作

原则二:不要一次性暴露所有能力

错误方式:500 Tools 全部暴露给 Model。

更合理:Category → Skill → Tool,即 Progressive Disclosure

原则三:Tool 不只是能力,也是控制边界

Structured Tool 可以提供 Permission、Hook、Validation、Audit、Retry、Timeout。因此 Tool 层同时承担能力抽象 + 执行控制

原则四:模型负责「不确定」,程序负责「确定」

这是整个 Harness 设计中最重要的边界:

                Agent
                  │
       ┌──────────┴──────────┐
       │                     │
  不确定的问题           确定的问题
       │                     │
      LLM                  Code
       │                     │
  判断 / 推理             执行 / 控制

17. Harness ≠ Tool 集合

一个常见误区是:Harness 就是很多 Tool。不是。Tool 只是 Harness 的一个组成部分。

更完整的结构应该是:

Harness
│
├── Model Integration
├── Agent Loop
├── Tool System
├── Skill System
├── Sandbox
├── Permission
├── Context Management
├── State Management
├── Memory
├── Checkpoint
├── Artifact
├── Orchestration
├── Observability
├── Evaluation
├── Scheduling
└── Isolation

所以:Tool ⊂ Harness,而不是 Harness = Tool。

18. Harness ≠ Agent

也不能简单认为 Agent = LLM。更准确的是:

Agent
│
├── Model
└── Harness

其中 Model 负责产生智能,Harness 负责把智能变成实际执行能力。

因此同一个 Model:

Model A
  ├── Harness 1 → Agent 1
  ├── Harness 2 → Agent 2
  └── Harness 3 → Agent 3

最终表现可能完全不同。

19. 与 LangGraph / DeepAgents 的关系

从工程角度看,可以把它们放到同一张图里理解:

                Agent Application
                       │
                     Agent
                       │
                    Harness
                       │
       ┌───────────────┼────────────────┐
       │               │                │
   Agent Loop       Tool/Skill       Runtime
       │               │                │
   LangGraph        LangChain       Sandbox
   StateGraph       Tools           Backend
   Checkpoint       Middleware      Memory
                                   Artifact
                                   Trace

需要注意:LangGraph、DeepAgents 并不等于 Harness 本身。 它们提供的是构建 Harness 的不同层次能力。

而完整生产系统还可能需要 Sandbox、Permission、Observability、Eval、Scheduling、Resource Governance、Artifact。

所以实际项目中经常是:

DeepAgents / LangGraph
  + Sandbox + Storage + Observability + Eval + Business Logic
  ↓
完整 Harness

20. 最终理解

如果只记住一句话:

Harness 就是围绕 Model 构建的一整套 Agent Runtime,让模型负责「想什么、怎么判断」,而系统负责「怎么执行、在哪里执行、能执行什么、失败怎么办、状态怎么保存以及如何继续运行」。

进一步压缩:

Model   = Intelligence
Harness = Execution Infrastructure
Agent   = Intelligence + Execution Infrastructure

而 Harness 的演进过程,本质上就是:

让 LLM 能做事
    ↓
让 LLM 安全地做事
    ↓
让 LLM 高效地做事
    ↓
让 LLM 长时间稳定地做事
    ↓
让 LLM 可以被观测、评估、恢复、调度和扩展

这也是为什么一个最初只有 LLM + Tool Call 的 Agent,最终很容易逐渐演化成:

Model + Agent Loop + Tool + Skill + Sandbox + Permission
+ Context + State + Memory + Checkpoint + Artifact
+ Orchestration + Trace + Eval + Scheduling + Isolation

最终形成的已经不是一个简单的 Agent,而是一套 Agent Runtime / Harness

换一个角度看,Harness 很多时候并不是在给模型「加功能」,而是在把东西从模型身上拿下来:

这些东西程序系统本来就能搞定,那就系统搞定。最后留给模型的,还是那些它最值钱的部分:理解、判断、推理、规划、创造

剩下的脏活,Harness 帮它兜住。

所以 DeepSeek 那句:

Agent = Model + Harness

现在确实越来越能理解。

同一个 Model,换一个 Harness,最后出来的东西,真的可能完全不像同一个 Agent。

<完>

参考: https://linux.do/t/topic/2797040

使用 Discussions 讨论 Github 上编辑 分享到 Twitter